//
//  NetRequestWithCahce.m
//  why
//
//  Created by Yinjialiang on 16/1/27.
//  Copyright © 2016年 刘赞黄Telen. All rights reserved.
//

#import "NetRequestWithCahce.h"
#import "NetCacheData.h"
#import "ConstDefine.h"
@implementation NetRequestWithCahce{
    NSMutableArray *allTaskArray;
    dispatch_queue_t _TaskQueue;
}

static NetRequestWithCahce *singleNetRequestWithCache = nil;

+(NetRequestWithCahce *)shareSingle{
    if (singleNetRequestWithCache == nil) {
        singleNetRequestWithCache = [[NetRequestWithCahce alloc] init];
    }
    return singleNetRequestWithCache;
}

-(instancetype)init{
    self = [super init];
    if (self) {
        allTaskArray = [NSMutableArray array];
        _portKeysArray = [NSMutableArray array];
        _TaskQueue = dispatch_queue_create("taskQueue", NULL);
    }
    return self;
}


-(void)netRequestWithCacheType:(RequestType)requestType Port:(NSString *)port baseUrl:(NSString *)baseUrl parameters:(NSDictionary*)dict  keyID:(NSString *)keyId successAndIsNeedCache:(BOOL (^)(NSDictionary* retDict,BOOL hasCache))successAndCache failure:(void (^)(NSError *error,BOOL hasCache))failure cache:(void (^)(NSDictionary * cacheRetDict))cacheBack timeOut:(CGFloat)timeOut{
    
    [self netRequestWithCacheType:requestType Port:port baseUrl:baseUrl parameters:dict keyID:keyId successAndIsNeedCache:^BOOL(NSDictionary *retDict, BOOL hasCache) {
        BOOL ret = YES;
        if (successAndCache) {
            ret = successAndCache(retDict,hasCache);
        }
        return ret;
    } failure:^(NSError *error, BOOL hasCache) {
        if (failure) {
            failure(error,hasCache);
        }
    } cache:^(NSDictionary *cacheRetDict) {
        if (cacheBack) {
            cacheBack(cacheRetDict);
        }
    } timeOut:timeOut timeLimitedType:TimeLimited_None ParamsIsJson:NO];
}

//带缓存的网络请求(适配PEP请求格式)
-(void)netRequestIsJsonParamsWithCacheType:(RequestType)requestType Port:(NSString *)port baseUrl:(NSString *)baseUrl parameters:(NSDictionary*)dict  keyID:(NSString *)keyId successAndIsNeedCache:(BOOL (^)(NSDictionary* retDict,BOOL hasCache))successAndCache failure:(void (^)(NSError *error,BOOL hasCache))failure cache:(void (^)(NSDictionary * cacheRetDict))cacheBack timeOut:(CGFloat)timeOut{
    [self netRequestWithCacheType:requestType Port:port baseUrl:baseUrl parameters:dict keyID:keyId successAndIsNeedCache:^BOOL(NSDictionary *retDict, BOOL hasCache) {
        BOOL ret = YES;
        if (successAndCache) {
            ret = successAndCache(retDict,hasCache);
        }
        return ret;
    } failure:^(NSError *error, BOOL hasCache) {
        if (failure) {
            failure(error,hasCache);
        }
    } cache:^(NSDictionary *cacheRetDict) {
        if (cacheBack) {
            cacheBack(cacheRetDict);
        }
    } timeOut:timeOut timeLimitedType:TimeLimited_None ParamsIsJson:YES];
}

-(void)netRequestWithCacheType:(RequestType)requestType Port:(NSString *)port baseUrl:(NSString *)baseUrl parameters:(NSDictionary*)dict  keyID:(NSString *)keyId successAndIsNeedCache:(BOOL (^)(NSDictionary* retDict,BOOL hasCache))successAndCache failure:(void (^)(NSError *error,BOOL hasCache))failure cache:(void (^)(NSDictionary * cacheRetDict))cacheBack timeOut:(CGFloat)timeOut timeLimitedType:(TimeLimitedType)timeLimitedType ParamsIsJson:(BOOL)isJson{
    
    //获取cache的数据
    [[NetCacheData shareSingle] getNetChacheDataWithPort:port baseUrl:baseUrl keyID:keyId completed:^(NSDictionary *cacheRetDict) {
        
        BOOL hasCache = NO;
        if (cacheRetDict) {
            hasCache = YES;
        }
        ////
        __block NSTimeInterval currentTime = 0;
        void(^askWork_do)(void) =  ^{
            //网络请求
            if (requestType == RequestType_Get) {
                
                [self getFormNetParamsIsJson:isJson Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
                    [DataProcessing do_Main_quick:^{
                        BOOL isNeedCache = YES;
                        if (successAndCache) {
                            isNeedCache = successAndCache(retDict,hasCache);
                        }
                        if (isNeedCache) {
                            NSDate *currentDate = [NSDate dateWithTimeIntervalSince1970:currentTime];
                            retDict.cacheDate = currentDate;
                            [[NetCacheData shareSingle] addNetCacheDataWithPort:port baseUrl:baseUrl keyID:keyId andResponseDic:retDict];
                        }
                        [self.portKeysArray addObject:keyId];
                    }];
                } failure:^(NSError *error) {
                    [DataProcessing do_Main_quick:^{
                        failure(error,hasCache);
                    }];
                } timeOut:timeOut];
                
            }else if(requestType == RequestType_Post){
                [self postFormNetParamsIsJson:isJson Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
                    [DataProcessing do_Main_quick:^{
                        BOOL isNeedCache = YES;
                        if (successAndCache) {
                            isNeedCache = successAndCache(retDict,hasCache);
                        }
                        if (isNeedCache) {
                            NSDate *currentDate = [NSDate dateWithTimeIntervalSince1970:currentTime];
                            retDict.cacheDate = currentDate;
                            [[NetCacheData shareSingle] addNetCacheDataWithPort:port baseUrl:baseUrl keyID:keyId andResponseDic:retDict];
                        }
                        [self.portKeysArray addObject:keyId];
                    }];
                    
                } failure:^(NSError *error) {
                    [DataProcessing do_Main_quick:^{
                        failure(error,hasCache);
                    }];
                } timeOut:timeOut];
            }
        };
        //
        if (cacheBack) {
            [DataProcessing do_Main_quick:^{
                cacheBack(cacheRetDict);
            }];
        }
        ////
        if (timeLimitedType == TimeLimitedFive_Minutes) {
            [self isLimitedTimeOutWithPort:port baseUrl:baseUrl keyId:keyId netRequestTime:^(NSTimeInterval currentRequestTime) {
                currentTime = currentRequestTime;
            } complete:^(BOOL timeLimited) {
                if (!timeLimited) {
                    [DataProcessing do_Main_quick:^{
                        if (successAndCache) {
                            successAndCache(nil,hasCache);
                        }
                    }];
                }
                if(timeLimited)(askWork_do());
            }];
        }else{
            askWork_do();
        }
        
    }];
}

//单纯网络请求
- (void)netRequestWithType:(RequestType)requestType Port:(NSString*)port andBaseUrl:(NSString*)baseUrl parameters:(NSDictionary*)dict success:(void (^)(NSDictionary* retDict))success failure:(void (^)(NSError *error))failure{
    if (requestType == RequestType_Get) {
        [self getFormNetParamsIsJson:NO Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
            success(retDict);
        } failure:^(NSError *error) {
            failure(error);
        } timeOut:60];
    }else if (requestType == RequestType_Post){
        [self postFormNetParamsIsJson:NO Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
            success(retDict);
        } failure:^(NSError *error) {
            failure(error);
        } timeOut:60];
    }
}

//单纯网络请求(适配PEP请求格式)
-(void)netRequestWithJsonParamsType:(RequestType)requestType Port:(NSString*)port andBaseUrl:(NSString*)baseUrl parameters:(NSDictionary*)dict success:(void (^)(NSDictionary* retDict))success failure:(void (^)(NSError *error))failure{
    if (requestType == RequestType_Get) {
        [self getFormNetParamsIsJson:YES Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
            success(retDict);
        } failure:^(NSError *error) {
            failure(error);
        } timeOut:60];
    }else if (requestType == RequestType_Post){
        [self postFormNetParamsIsJson:YES Port:port andBaseUrl:baseUrl parameters:dict success:^(NSDictionary *retDict) {
            success(retDict);
        } failure:^(NSError *error) {
            failure(error);
        } timeOut:60];
    }
}


//网络请求模块
//Get
- (void)getFormNetParamsIsJson:(BOOL)isJson Port:(NSString*)port andBaseUrl:(NSString*)baseUrl parameters:(NSDictionary*)dict success:(void (^)(NSDictionary* retDict))success failure:(void (^)(NSError *error))failure timeOut:(CGFloat)timeOut{
    
    [DataProcessing do_Async_quick:^{
        
        NSString *urlPath = [DataProcessing full_BaseUrl:baseUrl url:port];
#if __Debug_Net
        NSLog(@"URL:%@",urlPath);
        NSLog(@"Ref:%@",dict);
        NSDate* begin = [NSDate date];
#endif
        //创建一个AFN管理对象
        JRAFHTTPSessionManager *manager = [JRAFHTTPSessionManager manager];
        //告诉manager只下载原始数据, 不要解析数据
        //AFN即可以下载网络数据, 又可以解析json数据,如果不写下面的  自动就解析json
        if (isJson) {
            manager.requestSerializer = [JRAFJSONRequestSerializer serializer];
        }
        manager.responseSerializer = [JRAFHTTPResponseSerializer serializer];
        
        //设置超时时间
        manager.requestSerializer.timeoutInterval = timeOut;
        //发起POST网络请求
        NSURLSessionDataTask *task = [manager GET:urlPath parameters:dict success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
            [self removeTaskFromTaskArrayWithCurrentTask:task];
#if __Debug_Net
            NSTimeInterval time = [begin timeIntervalSinceNow];
            NSLog(@"网络耗费时间:%lf (%@)",time,urlPath);
#endif
            //解析返回的JSON数据
            NSData *responseData = [NSData dataWithData:responseObject];
            NSDictionary *dicMessage = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
            
#if __Debug_Net || __Debug_Net_Error
            if (dicMessage == nil) {
                NSLog(@"errorURL: %@",task.currentRequest);
                NSLog(@"size:%@ 完整data: %s",@(responseData.length),responseData.bytes);
                //
                [DataProcess do_Main_quick:^{
                    AppDelegate* appdelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
                    PopWebView* webview = [[PopWebView alloc] initWithFrame:appdelegate.window.bounds];
                    [webview.webview loadData:responseData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:task.originalRequest.URL];
                    webview.labelUrl.text = [task.originalRequest.URL absoluteString];
                    [appdelegate.window addSubview:webview];
                    [webview autoLayOut];
                    failure(nil);
                }];
            }
#endif
            
            if (dicMessage) {
                success(dicMessage);
            }
#if __Debug_Net
            NSTimeInterval time_ = [begin timeIntervalSinceNow];
            NSLog(@"累计耗费时间:%lf (%@)",time_,urlPath);
            NSLog(@"%@",dicMessage);
#endif
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self removeTaskFromTaskArrayWithCurrentTask:task];
#if __Debug_Net || __Debug_Net_Error
            NSLog(@"网络get错误 is %@",error);
#endif
#if __Debug_CancelTask
            if ([error.localizedDescription isEqualToString:NSLocalizedStringFromTable(@"netCancelled", @"WaWaYaYaCenter", @"")]) {
                NSLog(@"CancelURL:%@",urlPath);
            }
#endif
            failure(error);
        }];
        dispatch_async(_TaskQueue, ^{
            [allTaskArray addObject:task];
        });
        self.lastTask = task;
    }];
}


//Post
- (void)postFormNetParamsIsJson:(BOOL)isJson Port:(NSString*)port andBaseUrl:(NSString*)baseUrl parameters:(NSDictionary*)dict success:(void (^)(NSDictionary* retDict))success failure:(void (^)(NSError *error))failure timeOut:(CGFloat)timeOut{
    
    NSString *urlPath = [DataProcessing full_BaseUrl:baseUrl url:port];
#if __Debug_Net
    NSLog(@"URL:%@",urlPath);
    NSLog(@"Ref:%@",dict);
    NSDate* begin = [NSDate date];
#endif
    //创建一个AFN管理对象
    JRAFHTTPSessionManager *manager = [JRAFHTTPSessionManager manager];
    //告诉manager只下载原始数据, 不要解析数据
    //AFN即可以下载网络数据, 又可以解析json数据,如果不写下面的  自动就解析json
    if (isJson) {
        manager.requestSerializer = [JRAFJSONRequestSerializer serializer];
    }
    manager.responseSerializer = [JRAFHTTPResponseSerializer serializer];
    //设置超时时间
    manager.requestSerializer.timeoutInterval = timeOut;
    //发起POST网络请求
    NSURLSessionDataTask *task = [manager POST:urlPath parameters:dict success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        [self removeTaskFromTaskArrayWithCurrentTask:task];
#if __Debug_Net
        NSTimeInterval time = [begin timeIntervalSinceNow];
        NSLog(@"网络耗费时间:%lf (%@)",time,urlPath);
#endif
        //解析返回的JSON数据
        NSData *responseData = [NSData dataWithData:responseObject];
        NSDictionary *dicMessage = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
        
#if __Debug_Net || __Debug_Net_Error
        if (dicMessage == nil) {
            NSLog(@"errorURL: %@",task.currentRequest);
            NSLog(@"size:%@ 完整data: %s",@(responseData.length),responseData.bytes);
            //
            AppDelegate* appdelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
            PopWebView* webview = [[PopWebView alloc] initWithFrame:appdelegate.window.bounds];
            [webview.webview loadData:responseData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:task.originalRequest.URL];
            webview.labelUrl.text = [task.originalRequest.URL absoluteString];
            [appdelegate.window addSubview:webview];
            [webview autoLayOut];
            failure(nil);
        }
#endif
        
        if (dicMessage) {
            success(dicMessage);
        }
#if __Debug_Net
        NSTimeInterval time_ = [begin timeIntervalSinceNow];
        NSLog(@"累计耗费时间:%lf (%@)",time_,urlPath);
        NSLog(@"%@",dicMessage);
#endif
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self removeTaskFromTaskArrayWithCurrentTask:task];
#if __Debug_Net || __Debug_Net_Error
        NSLog(@"网络get错误 is %@",error);
#endif
#if __Debug_CancelTask
        if ([error.localizedDescription isEqualToString:NSLocalizedStringFromTable(@"netCancelled", @"WaWaYaYaCenter", @"")]) {
            NSLog(@"CancelURL:%@",urlPath);
        }
#endif
        failure(error);
    }];
    dispatch_async(_TaskQueue, ^{
        [allTaskArray addObject:task];
    });
    self.lastTask = task;
}

//上次请求时间是否超过限制时长(按接口)
//返回Yes 结束限制(进行网络请求)
-(void)isLimitedTimeOutWithPort:(NSString *)port baseUrl:(NSString *)baseUrl keyId:(NSString *)keyId netRequestTime:(void (^) (NSTimeInterval currentRequestTime))storeTime complete:(void (^)(BOOL isLimited))comp
{
    if(comp){
        NSTimeInterval currentTimestamps = [NSDate date].timeIntervalSince1970;
        [[NetCacheData shareSingle] getNetChacheDataWithPort:port baseUrl:baseUrl keyID:keyId completed:^(NSDictionary *cacheDict) {
            NSTimeInterval cacheTimestamps = cacheDict.cacheDate.timeIntervalSince1970;
            NSTimeInterval timeSub = currentTimestamps - cacheTimestamps;
            if (timeSub >= 300 && storeTime) {
                storeTime(currentTimestamps);
                comp(YES);
            }
            comp(NO);
        }];
    }
}
//请求成功或者请求失败清除对应task
-(void)removeTaskFromTaskArrayWithCurrentTask:(NSURLSessionDataTask*)task{
    dispatch_async(_TaskQueue, ^{
        for (NSURLSessionTask* tsk in allTaskArray) {
            if (tsk == task) {
                [allTaskArray removeObject:tsk];
                break;
            }
        }
    });
}

//取消网络请求
-(void)cancelAllTask{
    dispatch_async(_TaskQueue, ^{
        for (NSURLSessionDataTask *task in allTaskArray) {
            [task cancel];
        }
        [allTaskArray removeAllObjects];
    });
}

//获取指定接口是否正在请求
-(void)isRequestRuningWithPort:(NSString*)port baseUrl:(NSString*)baseUrl Completed:(void (^)(BOOL isRequesting))completed{
    __block BOOL isRequesting = NO;
    NSString *urlPath = [DataProcessing full_BaseUrl:baseUrl url:port];
    dispatch_async(_TaskQueue, ^{
        for (NSURLSessionDataTask *task in allTaskArray) {
            NSString *urlStr = [task.originalRequest.URL absoluteString];
            NSArray *urlSepArray = [urlStr componentsSeparatedByString:@"?"];
            NSString *urlPath_task = [urlSepArray firstObject];
            if ([urlPath_task isEqualToString:urlPath]) {
                isRequesting = YES;
                break;
            }
        }
        if (completed) {
            completed(isRequesting);
        }
    });
}

//取消指定的网络Task
-(void)cancelTaskWithPort:(NSString *)port baseUrl:(NSString *)baseUrl{

    NSString *urlPath = [DataProcessing full_BaseUrl:baseUrl url:port];
    dispatch_async(_TaskQueue, ^{
        for (NSURLSessionDataTask *task in allTaskArray) {
            NSString *urlStr = [task.originalRequest.URL absoluteString];
            NSArray *urlSepArray = [urlStr componentsSeparatedByString:@"?"];
            NSString *urlPath_task = [urlSepArray firstObject];
            if ([urlPath_task isEqualToString:urlPath]) {
                [task cancel];
                [allTaskArray removeObject:task];
            }
        }
    });
}

//获取对应接口的缓存
-(void)getCacheWithPort:(NSString*)port BaseUrl:(NSString*)baseUrl KeyId:(NSString*)keyId CacheBack:(void(^)(NSDictionary* retDict))cacheBack{
    [[NetCacheData shareSingle] getNetChacheDataWithPort:port baseUrl:baseUrl keyID:keyId completed:^(NSDictionary *cacheRetDict) {
        if (cacheBack) if (cacheBack) cacheBack(cacheRetDict);
    }];
}

//清除上次缓存时间
-(void)cleanLastLimitedDateWithPort:(NSString*)port BaseUrl:(NSString*)baseUrl keyID:(NSString*)keyId{
    [[NetCacheData shareSingle] getNetChacheDataWithPort:port baseUrl:baseUrl keyID:keyId completed:^(NSDictionary *cacheDict) {
        cacheDict.cacheDate = [NSDate dateWithTimeIntervalSince1970:0];
        [[NetCacheData shareSingle] addNetCacheDataWithPort:port baseUrl:baseUrl keyID:keyId andResponseDic:cacheDict];
    }];
}

@end
